﻿Namespace FileSystemScan
    Friend Class RescanQueue

        Private Shared mRescanQueue As New Generic.List(Of QueueItem)

        Public Class QueueItem
            Public DeadLine As Date
            Public Share As Entities.Share
            Public PathToScan As String
            Public RetryCount As Integer

            Friend Function GetStartsInAsTextEx() As String
                Dim tsStartsIn As TimeSpan = DeadLine.Subtract(Now)
                If tsStartsIn.TotalSeconds < 1 Then
                    Return "as soon as possible"
                Else
                    Return String.Format("as soon as possible after {0} seconds", CInt(tsStartsIn.TotalSeconds))
                End If
            End Function
        End Class

        Public Shared Sub Queue(ByVal share As Entities.Share, ByVal pathToScan As String, ByVal delay As TimeSpan)
            Dim clsItem As New QueueItem
            clsItem.Share = share
            If Not String.IsNullOrEmpty(pathToScan) Then clsItem.PathToScan = pathToScan.ToLower
            clsItem.DeadLine = Now.Add(delay)
            Queue(clsItem)
        End Sub
        Public Shared Sub ReQueue(ByVal item As QueueItem)
            item.RetryCount += 1
            item.DeadLine = Now.AddSeconds(30)
            Queue(item)
        End Sub

        Private Shared Sub Queue(ByVal item As QueueItem)
            SyncLock mRescanQueue
                Dim clsExistingItem As QueueItem = Nothing
                Select Case GetPathQueueStatus(item, clsExistingItem)
                    Case PathQueueStatus.NotQueued
                        mRescanQueue.Add(item)
                        FileShare.Engine.Manager.OnLogEvent(String.Format("Rescan of ""{0}"" queued to start {1}", item.Share.Name, item.GetStartsInAsTextEx))
                    Case PathQueueStatus.Queued
                        clsExistingItem.DeadLine = item.DeadLine
                        clsExistingItem.RetryCount = item.RetryCount
                        FileShare.Engine.Manager.OnLogEvent(String.Format("Rescan of ""{0}"" deadline changed to start {1}", item.Share.Name, clsExistingItem.GetStartsInAsTextEx))
                    Case PathQueueStatus.IsParentToQueued
                        For i As Integer = mRescanQueue.Count - 1 To 0 Step -1
                            Dim clsItem As QueueItem = mRescanQueue(i)
                            If Framework.IO.Utils.IsSubDir(clsItem.PathToScan, item.PathToScan) Then
                                mRescanQueue.RemoveAt(i)
                                FileShare.Engine.Manager.OnLogEvent(String.Format("Rescan of ""{0}"" removed from queue", item.Share.Name))
                            End If
                        Next
                        mRescanQueue.Add(item)
                        FileShare.Engine.Manager.OnLogEvent(String.Format("Rescan of ""{0}"" queued to start {1}", item.Share.Name, item.GetStartsInAsTextEx))
                    Case PathQueueStatus.ParentIsQueued
                        clsExistingItem.DeadLine = item.DeadLine
                        clsExistingItem.RetryCount = item.RetryCount
                        FileShare.Engine.Manager.OnLogEvent(String.Format("Rescan of ""{0}"" is included in queued scan for parent ""{1}"" and will start", item.Share.Name, clsExistingItem.PathToScan, clsExistingItem.GetStartsInAsTextEx))
                End Select
            End SyncLock
        End Sub
        Public Shared Function GetNextItemToScan() As QueueItem
            Dim dtClosest As Date = Date.MaxValue
            Dim clsSelected As QueueItem = Nothing
            SyncLock mRescanQueue
                For Each clsItem As QueueItem In mRescanQueue
                    If clsItem.DeadLine < dtClosest And clsItem.DeadLine < Now Then
                        dtClosest = clsItem.DeadLine
                        clsSelected = clsItem
                    End If
                Next
                If clsSelected IsNot Nothing Then mRescanQueue.Remove(clsSelected)
            End SyncLock
            Return clsSelected
        End Function

        Private Enum PathQueueStatus
            NotQueued
            ParentIsQueued
            IsParentToQueued
            Queued
        End Enum

        Private Shared Function GetPathQueueStatus(ByVal item As QueueItem, ByRef ret_Item As QueueItem) As PathQueueStatus
            For Each clsItem As QueueItem In mRescanQueue
                For i As Integer = 0 To clsItem.Share.Paths.Count - 1
                    Dim strPathToScan As String
                    If String.IsNullOrEmpty(clsItem.PathToScan) Then
                        strPathToScan = clsItem.Share.Paths(i)
                    Else
                        strPathToScan = clsItem.PathToScan
                    End If
                    For j As Integer = 0 To item.Share.Paths.Count - 1
                        Dim strPathToScan2 As String
                        If String.IsNullOrEmpty(item.PathToScan) Then
                            strPathToScan2 = item.Share.Paths(j)
                        Else
                            strPathToScan2 = item.PathToScan
                        End If

                        If item.PathToScan = strPathToScan Then
                            ret_Item = clsItem
                            Return PathQueueStatus.Queued
                        ElseIf Framework.IO.Utils.IsSubDir(strPathToScan2, strPathToScan) Then
                            ret_Item = clsItem
                            Return PathQueueStatus.IsParentToQueued
                        ElseIf Framework.IO.Utils.IsSubDir(strPathToScan, strPathToScan2) Then
                            ret_Item = clsItem
                            Return PathQueueStatus.ParentIsQueued
                        End If
                        If Not String.IsNullOrEmpty(item.PathToScan) Then Exit For
                    Next
                    If Not String.IsNullOrEmpty(clsItem.PathToScan) Then Exit For
                Next
            Next
            ret_Item = Nothing
            Return PathQueueStatus.NotQueued
        End Function
    End Class
End Namespace